/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.msu.common;

import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.transaction.JpaTransaction;
import io.iec.edp.caf.commons.transaction.TransactionPropagation;
import io.iec.edp.caf.msu.api.MsuService;
import io.iec.edp.caf.msu.api.ServiceUnitAwareService;
import io.iec.edp.caf.msu.api.client.ServiceDiscovery;
import io.iec.edp.caf.msu.api.entity.GspAppServerInstance;
import io.iec.edp.caf.msu.api.entity.GspSuInstance;
import io.iec.edp.caf.msu.api.entity.ServiceUnitInfo;
import io.iec.edp.caf.msu.api.enums.DeployMode;
import io.iec.edp.caf.msu.common.domain.converter.GspAppConverter;
import io.iec.edp.caf.msu.common.domain.converter.GspSuConverter;
import io.iec.edp.caf.msu.common.domain.repository.AppServerRepository;
import io.iec.edp.caf.msu.common.domain.repository.SuRepository;
import io.iec.edp.caf.tenancy.api.context.MultiTenantContextInfo;
import io.iec.edp.caf.tenancy.core.context.MultiTenantContextHolder;
import lombok.var;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * @author Leon Huo
 */
public class MsuServiceImpl implements MsuService {

    private AppServerRepository appRepo;
    private SuRepository suRepo;
    private ServiceUnitAwareService suAware;

    //系统微服务感知服务
    private ServiceDiscovery serviceDiscovery;

    public MsuServiceImpl(AppServerRepository appRepo, SuRepository suRepo, ServiceUnitAwareService suAware, ServiceDiscovery serviceDiscovery) {
        this.appRepo = appRepo;
        this.suRepo = suRepo;
        this.suAware = suAware;
        this.serviceDiscovery = serviceDiscovery;
    }

    @Override
    public DeployMode getDeployMode(String appServerName) {
        var deployMode = (DeployMode) CafEnvironment.getEnvironment().getProperty("msu.deployMode", DeployMode.class, DeployMode.OnPremise);
        return deployMode;
    }

    @Override
    public String getIpAddress(String appServerName) {
        var app = this.appRepo.findById(appServerName);
        if (app.isPresent()) {
            return app.get().getIp();
        } else {
            return "";
        }
    }

    /**
     * 获取appSever的port
     *
     * @param appServerName appServer名称
     * @return
     */
    @Override
    public String getPort(String appServerName) {
        var app = this.appRepo.findById(appServerName);
        if (app.isPresent()) {
            return app.get().getPort();
        } else {
            return "";
        }
    }


    /**
     * 是否本地调用
     *
     * @param serviceUnitName su的名称
     * @return
     */
    @Override
    public boolean isLocalInvoke(String serviceUnitName) {
        boolean check = true;

        //判断当前Server内是否存在SU
        return this.suAware.getEnabledServiceUnits().stream().anyMatch(d -> d.equalsIgnoreCase(serviceUnitName));
    }


    /**
     * 获取远程su的baseUrl
     *
     * @param appName
     * @return
     */
    @Override
    public String getRemoteBaseUrl(String appName) {
        var app = this.appRepo.findById(appName);
        if (app.isPresent()) {

            return app.get().getAppUrl();
        } else {
            return "";
        }
    }

    @Override
    public List<GspAppServerInstance> getGspAppServerInfo(String appServerName) {
        var entities = appRepo.findByAppName(appServerName);
        var instanceList = new ArrayList<GspAppServerInstance>();
        for (var entity : entities) {
            instanceList.add(GspAppConverter.convertToInstance(entity));
        }
        return instanceList;
    }

    @Override
    public List<GspAppServerInstance> getGspAppServerInfoBySu(String suName) {
        JpaTransaction tran = JpaTransaction.getTransaction();
        try {
            //在master数据库获取目标su
            MultiTenantContextInfo multiTenantContextInfo = new MultiTenantContextInfo();
            multiTenantContextInfo.setMasterDb(true);
            MultiTenantContextHolder.set(multiTenantContextInfo);
            //此处支持更多选项
            tran.begin(TransactionPropagation.REQUIRES_NEW);

            var apps = appRepo.findBySuName(suName.toLowerCase());
            if (apps == null || apps.size() == 0) {
                apps = appRepo.findBySuName(suName);
            }
            //重置数据库信息
            MultiTenantContextHolder.set(null);
            tran.commit();
            var instanceList = new ArrayList<GspAppServerInstance>();
            for (var entity : apps) {
                instanceList.add(GspAppConverter.convertToInstance(entity));
            }
            return instanceList;
        } catch (Throwable e) {
            tran.rollback();
            throw e;
        }
    }

    @Override
    public GspSuInstance getGspSuInfo(String suName) {
        return GspSuConverter.convertToInstance(suRepo.findById(suName).get());
    }

    @Override
    public List<GspSuInstance> getGspSuByAppServer(String appServerName) {
        var entities = suRepo.findByApp(appServerName);

        var instanceList = new ArrayList<GspSuInstance>();
        for (var entity : entities) {
            instanceList.add(GspSuConverter.convertToInstance(entity));
        }
        return instanceList;
    }

    @Override
    public List<ServiceUnitInfo> getEnabledServiceUnit() {
        return this.serviceDiscovery.getEnabledServiceUnitInfo();
    }


    private String getRequestUrl() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes != null) {
            HttpServletRequest request = servletRequestAttributes.getRequest();
            return request.getRequestURL().toString();
        }
        return null;
    }

    /**
     * 此方法描述的是：获得服务器的IP地址(多网卡)
     */
    private List<String> getLocalIPS() {
        InetAddress ip = null;
        List<String> ipList = new ArrayList<String>();
        try {
            Enumeration<NetworkInterface> netInterfaces = (Enumeration<NetworkInterface>) NetworkInterface
                    .getNetworkInterfaces();
            while (netInterfaces.hasMoreElements()) {
                NetworkInterface ni = (NetworkInterface) netInterfaces
                        .nextElement();
                Enumeration<InetAddress> ips = ni.getInetAddresses();
                while (ips.hasMoreElements()) {
                    ip = (InetAddress) ips.nextElement();
                    if (!ip.isLoopbackAddress()
                            && ip.getHostAddress().matches(
                            "(\\d{1,3}\\.){3}\\d{1,3}")) {
                        ipList.add(ip.getHostAddress());
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return ipList;
    }
}
